Skip to content

Add scipy.linalg.lu() decomposition support#2787

Open
abagusetty wants to merge 14 commits intoIntelPython:masterfrom
abagusetty:linalg_lu
Open

Add scipy.linalg.lu() decomposition support#2787
abagusetty wants to merge 14 commits intoIntelPython:masterfrom
abagusetty:linalg_lu

Conversation

@abagusetty
Copy link

This PR adds dpnp.scipy.linalg.lu() with support for all three output modes: default (P, L, U), permute_l=True (PL, U), and p_indices=True (p, L, U), including batched inputs.

Fixes: #2786

  • Have you provided a meaningful PR description?
  • Have you added a test, reproducer or referred to an issue with a reproducer?
  • Have you tested your changes locally for CPU and GPU devices?
  • Have you made sure that new changes do not introduce compiler warnings?
  • Have you checked performance impact of proposed changes?
  • Have you added documentation for your changes, if necessary?
  • Have you added your changes to the changelog?

@intel-python-devops
Copy link

Can one of the admins verify this patch?

@antonwolfy antonwolfy added this to the 0.20.0 release milestone Mar 2, 2026
Copy link
Contributor

@antonwolfy antonwolfy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@abagusetty, thank you for the contribution. I posted few comments below

from ._decomp_lu import lu, lu_factor, lu_solve

__all__ = [
"lu",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please state the change in the CHANGELOG.md?

usm_type=a_usm_type,
sycl_queue=a_sycl_queue,
)
up = dpnp.array(a, dtype=res_type)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like scipy might return input array a if dtype matches expected and overwrite_a is True:

Suggested change
up = dpnp.array(a, dtype=res_type)
up = dpnp.astype(a, dtype=res_type, copy=not overwrite_a)

Comment on lines 606 to 611
inv_perm = dpnp.zeros(
(*batch_shape, 1),
dtype=dpnp.int64,
usm_type=a_usm_type,
sycl_queue=a_sycl_queue,
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can use zeros_like here also (that will simplify the code):

Suggested change
inv_perm = dpnp.zeros(
(*batch_shape, 1),
dtype=dpnp.int64,
usm_type=a_usm_type,
sycl_queue=a_sycl_queue,
)
inv_perm = dpnp.zeros_like(
a,
shape=(*batch_shape, 1),
dtype=dpnp.int64,
)

)

# ---- Fast path: empty arrays ----
elif a.size == 0:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can use empty_like for below calls


# The permutation matrix P uses a real dtype (SciPy convention):
# P only contains 0s and 1s, so complex storage would be wasteful.
real_type = _get_real_dtype(res_type)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we reuse _real_type here instead?

Suggested change
real_type = _get_real_dtype(res_type)
real_type = _real_type(res_type)

usm_type=a_usm_type,
sycl_queue=a_sycl_queue,
)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be better (and faster) just to return here and in scalar path above to avoid possible below calls of _apply_permutation_to_rows?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, the empty path previously used dpnp.empty_like for perm_matrix to skip the gather entirely, but since both eye_m and inv_perm are empty arrays, _apply_permutation_to_rows on them is a no-op. Also to deal with multiple returns, I have created a helper method _assemble_lu_output to reduce the clutter and please pylint warning

a[1, 0, 0] = dpnp.nan
assert_raises(ValueError, dpnp.scipy.linalg.lu, a, check_finite=True)


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also enable muted corresponded tests in dpnp/tests/third_party/cupyx/scipy_tests/linalg_tests/test_decomp_lu.py

abagusetty and others added 4 commits March 2, 2026 09:18
Co-authored-by: Anton <100830759+antonwolfy@users.noreply.github.com>
Co-authored-by: Anton <100830759+antonwolfy@users.noreply.github.com>
@abagusetty
Copy link
Author

@antonwolfy Thanks for taking time. All the suggestions were addressed. Please let me know

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

dpnp.scipy.linalg.lu missing although lu_factor / lu_solve are implemented

3 participants